﻿//  Copyright © Decebal Mihailescu 2013-2014
//  All rights reserved. This source code and binaries are distributed under 
//  Microsoft Public PatternLicense (Ms-PL)
//  The latest code is available at http://VSDesignPatterns.codeplex.com

//  Redistributions of source code must retain the above copyright notice, 
//  this list of conditions and the following disclaimer. 
//  Redistributions in binary form must reproduce the above copyright notice, 
//  this list of conditions and the following disclaimer in the documentation 
//  and/or other materials provided with the distribution. 

//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER 
//  REMAINS UNCHANGED.
using System;
using System.Xml;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;
using Microsoft.Win32;
using System.Diagnostics;
using System.ComponentModel;
using System.Text.RegularExpressions;

namespace Common
{
#if !VS2015
    using Ionic.Zip;
#endif
    public class Repository : IDisposable, IRepository
    {

        protected ILanguageProviderMetaData _ilpmd;
        protected IWizardWindow _iww;
        protected static readonly Regex _regex4Picture;
        protected static readonly Regex _regex4Patterns;
        private static readonly Lazy<string> _injectedScriptFormat;
#if VS2015
      
     //  protected static readonly string _injectionFolder = Path.Combine(Path.GetDirectoryName(MEFController.Instance.DPEntryAssembly.Location), "TemplateLibrary");
#endif
        protected static string InjectedScriptFormat
        {
            get { return _injectedScriptFormat.Value; }
        }

        public string PatternDefinitions;
        internal protected string TemplatesFolder;
        public StorageType SavedAs;
        static Repository()
        {
            _regex4Picture = new Regex("<\\s*img\\s+alt\\s*=\\s*\"Diagram\"\\s+src\\s*=\\s*\"(?<PATH>\\s*\\w+[.]{1}\\w{3}\\s*)\"\\s+border\\s*=\\s*\"0\"\\s*/\\s*>",
                RegexOptions.Multiline | RegexOptions.Compiled);
            _regex4Patterns = new Regex(@"<\s*a[^>]*?\s*href=""\s*""[^>]*>(?<text>.*)<[^<].*a\s*>");
            _injectedScriptFormat = new Lazy<string>(() =>
                {
                    string[] lines = new string[]
            {"<link href=\"{0}/shared/css/Site.css\" rel=\"stylesheet\" />",
            "<link href=\"{0}/shared/css/custom-theme/jquery-ui.custom.css\" rel=\"stylesheet\" />",
            "<script src=\"{0}/shared/js/jquery.js\"></script>",
           // "<script type=\"text/javascript\" src=\"{0}/shared/dp.js\"collapsedPrefix = \"[+]\" expandededPrefix = \"[-]\"></script>",
            "<script type=\"text/javascript\" src=\"{0}/shared/dp.js\"></script>",//use dpexpanded and dpcollapsed.js instead
           
            };
                    /*
        var collapsedPrefix = '[+]';
        var expandededPrefix = '[-]'; 
 // see also http://api.jqueryui.com/accordion/
       $(function () //doc ready
        {  
            $("a[href='']").click(function(e) 
            {
                //var str = $(this).attr("href");
                //if (str == null || !str || !str.trim())
                //{
                //alert('preventDefault');
                e.preventDefault();
                //alert($(this).text());
                window.external.ClientCallback($(this).text());
             }                      );//a[href='']").click ends
     
                //DisablePatternLinks();
                //ChangeAppearance('show', 'first');
                //CreateCollapsableTopics();
        });//ready ends
              
        //global functions
	    function ChangeAppearance(action, target, collapse, expand) 
	    {
	        collapsedPrefix = collapse;
            expandededPrefix = expand;
            $('.section').each(function () 
            {
                 var otext = $('h2', this).text();
		        //alert("text = " + text);
                $('h2', this).remove();//replace the header with a widget
                $('<div class="ui-widget-header" style="width:auto">' + collapsedPrefix + otext + '</div>')
                .insertBefore(this).click(function () {$(this).next().slideToggle(200);
							var prefix = $(this).text().substring(0,3);
							if(prefix == collapsedPrefix)
							    $(this).text(expandededPrefix + otext);
							if(prefix == expandededPrefix)
							    $(this).text(collapsedPrefix + otext);							    
						       })
                .mouseover(function () {$(this).css('cursor', 'pointer');})
                .next().hide();
            }                   );
        }
        
        function DisablePatternLinks()
        {
            $("a[href='']")
               .each(function()
               { 
                    var txt =$(this).text();
                    $(this).replaceWith(function(){ return  txt ;});    
                });
        }
        
	    function ChangeAppearance(action, target) 
	    {
            if(target == 'none')
            {
                return;
            }
            else
            {
                CreateCollapsableTopics();
            }
		    if(target == 'first')
		    {
		        if(action == 'hide')
		        {
				    $('.section:first').hide();	
				    var txt = $('.section:first').prev().text().substring(3);
				    $('.section:first').prev().text(collapsedPrefix + txt);				    
				}	    
		        else
		        {
				    $('.section:first').show();
				    var txt = $('.section:first').prev().text().substring(3);
				    $('.section:first').prev().text(expandededPrefix + txt);
				}
		    }
		    else if(target == 'last')
		    {
	            if(action == 'hide')
			        $('.section:last').hide();		    
	            else
			        $('.section:last').show();					
	        }
		    else
		    {
			    $('.section').each(function () 
			    {
				    if(action == 'hide')
					    $(this).hide();
				    else
				    {
					    $(this).show();
				    var txt = $('.section:first').prev().text().substring(3);
				    $(this).prev().text(expandededPrefix + txt);					     
					}

			    }                 );
		    }
	    }    */
                    return string.Join(Environment.NewLine, lines);
                });
        }
        public Repository()
        {
        }
        public void UpdatePicture(ITemplatePattern itp, IWizardWindow iww)
        {
            string newlocation = itp.Picture;
            string prevLocation = iww.Diagram.Tag as string;
            if (newlocation != prevLocation)
            {

                IRepository irep = this;
                if (irep != null)
                {
                    Stream strp = irep[newlocation];
                    if (strp != null)
                    {
                        iww.LoadImageFromStream(strp);
                        strp.Close();
                    }
                }

                iww.Diagram.Tag = newlocation;

            }

        }
        virtual public void UpdateDescription(ITemplatePattern itp, IWizardWindow iww)
        {
            string path = itp.Description;
            switch (itp.DescriptionStoredAs)
            {
                case StorageType.Text:
                    string txt = itp.Description.Replace(@"\r\n", Environment.NewLine).Replace(@"\n", Environment.NewLine);
                    //iww.WBDescription.Visible = false;
                    iww.RTBDescription.Visible = true;
                    iww.RTBDescription.Text = txt;
                    iww.RTBDescription.Tag = null;//no caching
                    break;

                case StorageType.Url:
                    UpdateBrowserDescription(iww, itp, path);
                    break;
                case StorageType.FileSystem:

                    if (string.IsNullOrEmpty(path))
                    {
                        iww.RTBDescription.Visible = true;
                        iww.RTBDescription.Text = string.Format("There is no file or text description for the pattern {0}!", itp.PatternName);
                        iww.RTBDescription.Tag = null;
                    }
                    else
                    {
                        switch (Path.GetExtension(path).ToUpperInvariant())
                        {
                            case ".TXT":
                                //iww.WBDescription.Visible = false;
                                //iww.RTBDescription.Visible = true;
                                UpdateRTFDescription(iww, itp, path, RichTextBoxStreamType.PlainText);
                                iww.OnlineResources.Visible = true;
                                break;
                            case ".HTML":
                            case ".HTM":
                                UpdateBrowserDescription(iww, itp, path);
                                break;
                            case ".RTF":
                                UpdateRTFDescription(iww, itp, path, RichTextBoxStreamType.RichText);
                                iww.OnlineResources.Visible = true;
                                break;
                            default://url
                                UpdateBrowserDescription(iww, itp, path);
                                break;

                        }
                    }
                    break;

                default://not implemented
                    throw new NotSupportedException(SavedAs + " storage type is not supported by UpdateDescription");
                    // break;
            }
        }

        static protected readonly Regex _regExOnlineRes = new Regex(@"<a\s*href\s*=\s*"".+""\s+target\s*="".+""\s*>.+<\s*/a\s*\s*>", RegexOptions.Singleline | RegexOptions.Compiled);
        protected void UpdateBrowserDescription(IWizardWindow iww, ITemplatePattern itp, string url)
        {
            iww.RTBDescription.Visible = false;
            iww.WBDescription.Visible = true;
            string prevUrl = iww.WBDescription.Tag as string;
            if (url == prevUrl)
                return;



            if (url.StartsWith("http", StringComparison.InvariantCultureIgnoreCase))
                iww.WBDescription.Navigate(url, false);//must change to html control
            else
            { //this is an html local file
                // 2 way communication form <-->webBrowser at: https://msdn.microsoft.com/en-us/library/a0746166.aspx
                //insert the script before loading
                string newDocTxt = File.ReadAllText(url);
                string strPath = GetPatternsDir();
                /*
#if VS2015
                string strPath = GetDevelopmentPatternsDir();// _injectionFolder;
#else
                string strPath = GetDevelopmentPatternsDir();
#endif
*/
                newDocTxt = newDocTxt.Replace("<!--myInjectedScript-->", GetNewScript(strPath));
                string pathp = Path.Combine(Path.Combine(strPath, itp.PatternName).ToString(), itp.Picture);// string.Format("\\{0}\\{1}",itp.PatternName, itp.Picture));
                newDocTxt = _regex4Picture.Replace(newDocTxt, "<img alt=\"Diagram\" src=\"" + pathp + "\" border=\"0\"/>");
                iww.WBDescription.DocumentText = newDocTxt;//Encoding??
            }
            iww.WBDescription.Tag = url;
            if (File.Exists(url) && string.Compare(url, itp.OnlineResources, true) < 0)
            {
                iww.OnlineResources.Visible = !Utils.HideOnlineLink;
            }
            else
                iww.OnlineResources.Visible = false;
        }

        protected string GetNewScript(string repPath)
        {
            return string.Format(InjectedScriptFormat, repPath);
            //  MessageBox.Show("regPath =" + repPath, "info"); //just debug

            /*
<!--myInjectedScript-->
<!--
    <link href="C:\Sandbox\Designpatterns\Misc\TemplateLibrary/shared/css/Site.css" rel="stylesheet" />
    <link href="C:\Sandbox\Designpatterns\Misc\TemplateLibrary/shared/css/custom-theme/jquery-ui.custom.css" rel="stylesheet" />

    <script src="C:\Sandbox\Designpatterns\Misc\TemplateLibrary/shared/js/jquery.js"></script>
    
    <script>
        $(function (){
            $("a[href='']").click(function(e) { 
                e.preventDefault();window.external.ClientCallback($(this).text()); });
        });
        
        function CreateCollapsableTopics(){
        
            $('.section').each(function () { 
           
                var text = $('h2', this).text();
                $('h2', this).remove();//replace the header with a widget
                $('<div class="ui-widget-header" style="width:auto">' + text + '</div>')
                .insertBefore(this).click(function () {$(this).next().slideToggle(200);})
                .mouseover(function () {$(this).css('cursor', 'pointer');})
                .next().hide();}); }
       
        
        function DisablePatternLinks(){
        
            $("a[href='']") .each(function(){ 
              
               
                    var txt =$(this).text();

                    $(this).replaceWith(function(){ return  txt ;});    
                });}
        
        
	    function ChangeAppearance(action, target) {
	    
            if(target == 'none')
                return;
            else{ CreateCollapsableTopics();}
            
               
            
		    if(target == 'first') {
		   
		        if(action == 'hide')
				    $('.section:first').hide();		    
		        else
				    $('.section:first').show();}
		    
		    else if(target == 'last') {
		   
	            if(action == 'hide')
			        $('.section:last').hide();		    
	            else
			        $('.section:last').show();}	 else				
	        
		   
		    {$('.section').each(function () { 
			    
			   
				    if(action == 'hide')
					    $(this).hide();
				    else
					    $(this).show(); });} } 
    </script>   
-->
             */

        }

        protected static void UpdateRTFDescription(IWizardWindow iww, ITemplatePattern itp, string path, RichTextBoxStreamType streamType)
        {
            iww.RTBDescription.Visible = true;
            iww.WBDescription.Visible = false;

            string prevPath = iww.RTBDescription.Tag as string;
            if (File.Exists(path))
            {
                if (path != prevPath)
                {
                    IRepository irep = itp.GetAsService<IRepository>();
                    Stream str = irep[path];
                    iww.RTBDescription.LoadFile(str, streamType);
                    str.Close();
                    iww.RTBDescription.Tag = path;
                }
            }
            else
            {
                iww.RTBDescription.Tag = null;
                iww.RTBDescription.Text = string.Format("File '{0}' does not exist!", path);
            }
        }

        public void Init(ILanguageProvider ilp)
        {
            _ilpmd = ilp.GetAsService<ILanguageProviderMetaData>();
            _iww = ilp.GetAsService<IWizardWindow>();
            if (_iww != null)
            {


            }

            if (_ilpmd == null)
                SavedAs = StorageType.FileSystem;
            else
                SavedAs = _ilpmd.SavedAs;
            //RegistryKey regck = Registry.CurrentUser.OpenSubKey(Common.Utils.AppHive, false);
            //if (regck != null)
            //{
            //    TemplatesFolder = regck.GetValue("TemplateLibPath", null, RegistryValueOptions.None) as string;
            //    regck.Close();
            //}
            if (string.IsNullOrEmpty(TemplatesFolder))// || !Directory.Exists(TemplatesFolder))
            {//not installed
#if VS2015
                string[] args = Environment.GetCommandLineArgs();
                string executable = Path.GetFileName(args[0]);
                if (Path.GetFileName(executable).ToUpperInvariant() == "DEVENV.EXE")
                {
                    string crtFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                    TemplatesFolder = Path.Combine(crtFolder, "TemplateLibrary");
                }
                else
                {
                    string crtdir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                    DirectoryInfo di = Directory.GetParent(crtdir);
                    if (di.FullName.EndsWith("x86", StringComparison.InvariantCultureIgnoreCase))
                        di = di.Parent;
                    TemplatesFolder = Path.Combine(di.Parent.Parent.FullName, @"Misc\TemplateLibrary");
                }

#else
                TemplatesFolder = GetPatternsDir();
#endif
            }
            if (_ilpmd == null && _ilpmd.LPIndexFile != null)
                PatternDefinitions = null;
            else
            {
                InitLocation();

            }
        }

        protected virtual void InitLocation()
        {
            switch (SavedAs)
            {
                case StorageType.FileSystem:
                    PatternDefinitions = System.IO.Path.Combine(TemplatesFolder, _ilpmd.LPIndexFile);
                    break;

                default:
                    throw new NotSupportedException(SavedAs + " storage type is not supported by InitLocation");
            }
        }
        public virtual Stream this[string newlocation]
        {
            get
            {

                if (_ilpmd == null)
                    return null;
                else
                {

                    switch (SavedAs)
                    {

                        case StorageType.FileSystem:
                            return File.OpenRead(newlocation);

                        default:
                            throw new NotImplementedException("this[string newlocation] does not handle " + SavedAs);

                    }

                }
                // Return an error string.
                //  return null;
            }

        }
        protected static string GetPatternsDir()
        {
           // string crtdir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            string crtdir = Path.GetDirectoryName(MEFController.Instance.DPEntryAssembly.Location);
            DirectoryInfo di = Directory.GetParent(crtdir);
            if (di.FullName.EndsWith("x86", StringComparison.InvariantCultureIgnoreCase))
                di = di.Parent;
            string[] args = Environment.GetCommandLineArgs();
            string executable = Path.GetFileName(args[0]);
           /* string repository = (_ilpmd == null) ? "TemplateLibrary" : "TemplateLibrary";// _ilpmd.LPRepositoryName;
              */
            string prgfld = Environment.GetEnvironmentVariable("programfiles");
            //  if (executable.ToUpperInvariant() == "DEVENV.EXE")
            if (di.FullName.IndexOf(prgfld, 0, StringComparison.InvariantCultureIgnoreCase) == 0)
                return Path.Combine(di.Parent.FullName, @"DesignPatterns for VS " + Utils.VSYear + "\\" + "TemplateLibrary");
            else
            {
                if (executable.ToUpperInvariant() == "DEVENV.EXE")
#if VS2015
                    return Path.Combine(crtdir, "TemplateLibrary");
#else
                    return Path.Combine(di.Parent.FullName, @"Misc\" + "TemplateLibrary");
#endif

                else
                    return Path.Combine(di.Parent.Parent.FullName, @"Misc\" + "TemplateLibrary");
            }
        }

        public virtual XmlReader GetIndex(IWin32Window iwnd)
        {
            XmlReader xmlReader = null;
            switch (SavedAs)
            {
                case StorageType.FileSystem:
                    if (!File.Exists(PatternDefinitions))
                    {
#if VS2015
                        IPackageInstall ipi = _iww.GetAsService<IPackageInstall>();
                        if (ipi != null)
                            ipi.PostInstallPackage(iwnd);
                        //check again
                        if (File.Exists(PatternDefinitions))
                        {
                            xmlReader = new XmlTextReader(File.OpenRead(PatternDefinitions));
                            break;
                        }
#endif
                        string err = string.Format("Can not find the file '{0}'!\r\nRestarting Visual Studio might fix it.", PatternDefinitions);
                        if (iwnd != null)
                        {
                            (iwnd as Control).ShowMessageBox(err, "Can not load templates from " + PatternDefinitions, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                        else
                            MessageBox.Show(err, "Can not load templates from " + PatternDefinitions, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        xmlReader = null;
                    }
                    else
                        xmlReader = new XmlTextReader(File.OpenRead(PatternDefinitions));
                    break;

                default:
                    xmlReader = null;
                    break;
            }
            return xmlReader;
        }
        virtual public string GetTemplatePath(string PatternName)
        {

            string defaultPath = null;
            switch (_ilpmd.SavedAs)
            {
                case StorageType.FileSystem:
                    defaultPath = Path.Combine(TemplatesFolder, string.Format("{0}\\{1}", PatternName, PatternName));
                    break;

                default:
                    throw new NotSupportedException(_ilpmd.SavedAs.ToString() + " storage type is not supportetd byGetTemplatePath");
            }
            return defaultPath;
        }
        protected static readonly string[] _descrExts = new string[] { ".htm", ".html", ".rtf", ".txt" };
        readonly static string _currentCulture = System.Windows.Forms.InputLanguage.CurrentInputLanguage.Culture.ThreeLetterISOLanguageName;
        public virtual void GetDescription(ITemplatePattern itp, XElement el)
        {
            StorageType DefaultStorage = (this._ilpmd == null) ? StorageType.FileSystem : _ilpmd.SavedAs;
            if (el == null)
            {
                itp.Description = null;
            }
            else
            {

                itp.DescriptionStoredAs = el.Attr2Enum<StorageType>("StoredAs", DefaultStorage);
                itp.Description = el.Value;
                if (itp.DescriptionStoredAs == StorageType.Text || itp.DescriptionStoredAs == StorageType.Url)
                    return;
            }
            itp.DescriptionStoredAs = DefaultStorage;
            switch (DefaultStorage)
            {
                case StorageType.FileSystem:
                    if (el == null)
                    {
                        string fileDescription = this.GetTemplatePath(itp.PatternName);
                        itp.Description = _descrExts.Select(e => string.Format("{0}_{1}{2}", fileDescription, _currentCulture, e))
                            .FirstOrDefault(s => File.Exists(s));
                        //check for Neutral language
                        if (itp.Description == null)
                        {
                            itp.Description = _descrExts.Select(e => fileDescription + e).FirstOrDefault(s => File.Exists(s));
                        }
                        if (itp.Description == null)
                        {
                            if (string.IsNullOrEmpty(itp.OnlineResources))
                            {
                                itp.Description = string.Format("There is no file or text description for the pattern '{0}'!", itp.PatternName);
                                itp.DescriptionStoredAs = StorageType.Text;
                            }
                            else
                            {
                                itp.DescriptionStoredAs = StorageType.Url;
                                itp.Description = itp.OnlineResources;
                            }
                        }
                    }
                    else
                    {
                        if (!Path.IsPathRooted(itp.Description))
                        {
                            itp.Description = Path.Combine(this.TemplatesFolder, string.Format("{0}\\{1}",
                                 itp.PatternName, itp.Description));
                        }
                    }
                    break;

                default:
                    throw new NotSupportedException(DefaultStorage.ToString() + " storage type is not supported for Description");
            }
        }

        protected static readonly string[] _pictExts = new string[] { ".png", ".jpg", ".gif", ".bmp" };
        public virtual void GetPicture(ITemplatePattern itp, XElement el)
        {
            StorageType defaultStorage = (this._ilpmd == null) ? StorageType.FileSystem : _ilpmd.SavedAs;
            if (el == null)
            {
                itp.PictureStoredAs = defaultStorage;
                itp.Picture = null;
            }
            else
            {
                itp.PictureStoredAs = el.Attr2Enum<StorageType>("StoredAs", defaultStorage);
                itp.Picture = el.Value;
            }
            switch (itp.PictureStoredAs)
            {
                case StorageType.FileSystem:
                    if (el == null)
                    {

                        string filePicture = this.GetTemplatePath(itp.PatternName);
                        itp.Picture = _pictExts.Select(e => filePicture + e).FirstOrDefault(s => File.Exists(s));
                        if (itp.Picture != null)
                            itp.PictureStoredAs = defaultStorage;
                    }
                    else
                    {
                        if (!Path.IsPathRooted(itp.Picture))
                        {
                            itp.Picture = Path.Combine(this.TemplatesFolder, string.Format("{0}\\{1}",
                                 itp.PatternName, itp.Picture));
                        }
                    }
                    break;

                default:
                    throw new NotSupportedException(itp.PictureStoredAs.ToString() + " storage type is not supported for pictures");
            }
        }
        protected virtual string GetCodeFolder(CodeLangEnum lang)
        {
            string codeFolder = null;
            switch (lang)
            {
                case CodeLangEnum.ManagedCpp:
                case CodeLangEnum.NativeCpp:
                    codeFolder = "Cpp";
                    break;
                default:
                    codeFolder = lang.ToString();
                    break;

            }
            return codeFolder;
        }
        public virtual string GetCodeFilePath(ITemplateFile itf)
        {

            if (Path.IsPathRooted(itf.FileTemplate))
                return itf.FileTemplate;


            string path = null;
            ITemplatePattern itp = itf.GetAsService<ITemplatePattern>();
            switch (itf.StoredAs)
            {
                case StorageType.FileSystem:
                    // use get service to get to the TemplatePattern
                    path = Path.Combine(this.TemplatesFolder, string.Format("{0}\\{1}\\{2}",
                itp.PatternName, GetCodeFolder(itp.CodeLanguage), itf.FileTemplate));
                    break;

                default:
                    throw new NotImplementedException("GetCodeFilePath does not handle " + itf.StoredAs);

            }
            return path;

        }

        public virtual void LoadTFContent(ITemplateFile itf)
        {
            try
            {
                string path = GetCodeFilePath(itf);
                TemplatePattern parentTemplate = itf.GetAsService<ITemplatePattern>() as TemplatePattern;
                ILanguageProvider ilp = parentTemplate.GetAsService<ILanguageProvider>();
                switch (itf.StoredAs)
                {
                    case StorageType.FileSystem:
                        if (!File.Exists(path))
                            return;
                        using (TextReader tr = File.OpenText(path))
                        {
                            itf.FileTemplateContent = tr.ReadToEnd();

                        }
                        break;

                    default:
                        throw new NotImplementedException("LoadTFContent does not handle " + itf.StoredAs);
                        //  break;
                }
            }
            catch //(Exception ex)
            {
                throw;
            }
        }
#region IDisposable Members

        virtual public void Dispose()
        {
            //    if (_zip != null)
            //    {
            //        _zip.Dispose();
            //    }
            //    GC.SuppressFinalize(this);
        }

#endregion
    }

#region CSharpProvider

    [ExportLanguageProvider(ProviderName = "Default CSharp", Description = "CSharp LangProvider",
    SupportedLangs = CodeLangEnum.CSharp, Extensions = new string[] { ".cs" },
    LPIndexFile = "CSharpTemplates.xml",
#if DEBUG
 SavedAs = StorageType.FileSystem)]
#else
    SavedAs = StorageType.FileSystem)]
#endif
    public sealed class DefaultCSharpProvider : BaseLanguageProvider<Repository, TemplatePattern>, ILanguageProvider
    {

        private DefaultCSharpProvider()
        {
            Logo = @"//This source code was generated using Visual Studio Design Patterns add-in
//You can find the source code and binaries at http://VSDesignPatterns.codeplex.com";
        }

#region IServiceProvider Members

        public override object GetService(Type serviceType)
        {
            if (serviceType == typeof(ILanguageProviderMetaData))
                return MEFController.Instance["Default CSharp"];
            return base.GetService(serviceType);
        }

#endregion
#region ILanguageProvider Members

#endregion
    }
#endregion

#region VBProvider



    [ExportLanguageProvider(ProviderName = "Default VB", Description = "VB LangProvider",
    SupportedLangs = CodeLangEnum.VB, Extensions = new string[] { ".vb" },
    LPIndexFile = "VBTemplates.xml",
#if DEBUG
 SavedAs = StorageType.FileSystem)]
#else
    SavedAs = StorageType.FileSystem)]
#endif
    public sealed class DefaultVBProvider : BaseLanguageProvider<Repository, TemplatePattern>, ILanguageProvider
    {

        private DefaultVBProvider()
        {
            Logo = @"'This source code was generated using Visual Studio Design Patterns add-in
'You can find the source code and binaries at http://VSDesignPatterns.codeplex.com";
        }
#region IServiceProvider Members

        public override object GetService(Type serviceType)
        {
            if (serviceType == typeof(ILanguageProviderMetaData))
                return MEFController.Instance["Default VB"];
            return base.GetService(serviceType);
        }

#endregion

#region ILanguageProvider Members
#endregion

        override protected string LineComment
        {
            get { return @"'"; }
        }
    }
#endregion

#region CPPProviders

    [ExportLanguageProvider(ProviderName = "Default NativeCPP", Description = "Native CPP LangProvider",
    SupportedLangs = CodeLangEnum.NativeCpp, CompatibleLangs = CodeLangEnum.ManagedCpp,
    Extensions = new string[] { ".h", ".cpp", ".cxx", ".cc", ".hpp", ".c", ".hxx", ".hh", ".tli", ".tlh", ".inl" },
    LPIndexFile = "CPPTemplates.xml",

#if DEBUG
 SavedAs = StorageType.FileSystem)]
#else
    SavedAs = StorageType.FileSystem)]
#endif
    public sealed class NativeCPPProvider : BaseLanguageProvider<Repository, TemplatePattern>, ILanguageProvider
    {

        private NativeCPPProvider()
        {
            Logo = @"//This source code was generated using Visual Studio Design Patterns add-in
//You can find the source code and binaries at http://VSDesignPatterns.codeplex.com";
        }
#region IServiceProvider Members

        public override object GetService(Type serviceType)
        {
            if (serviceType == typeof(ILanguageProviderMetaData))
                return MEFController.Instance["Default NativeCPP"];
            return base.GetService(serviceType);
        }

#endregion
#region ILanguageProvider Members


#endregion
    }


    [ExportLanguageProvider(ProviderName = "Default ManagedCPP", Description = "ManagedCPP LangProvider",
    SupportedLangs = CodeLangEnum.ManagedCpp,
    Extensions = new string[] { ".h", ".cpp", ".cxx", ".cc", ".hpp", ".c", ".hxx", ".hh", ".tli", ".tlh", ".inl" },
    LPIndexFile = "CPPTemplates.xml",
#if DEBUG
 SavedAs = StorageType.FileSystem)]
#else
    SavedAs = StorageType.FileSystem)]
#endif
    public sealed class ManagedCPPProvider : BaseLanguageProvider<Repository, TemplatePattern>, ILanguageProvider
    {

        private ManagedCPPProvider()
        {
            Logo = @"//This source code was generated using Visual Studio Design Patterns add-in
//You can find the source code and binaries at http://VSDesignPatterns.codeplex.com";
        }
#region IServiceProvider Members

        public override object GetService(Type serviceType)
        {
            if (serviceType == typeof(ILanguageProviderMetaData))
                return MEFController.Instance["Default ManagedCPP"];
            return base.GetService(serviceType);
        }

#endregion
#region ILanguageProvider Members


#endregion
    }
#endregion



    public class SearchProvider
    {
        public class Context
        {
            public string SelectedText { get; set; }
            //public WindowPopupEnum OriginalWnd { get; set; }
            public string Caption { get; set; }
            public IProjectInfo ProjectInfo { get; set; }
            //public SearchProvider SP { get; internal set; }
            public string Suffix { get; set; }
            public string SearchPhrase
            {
                get
                {
                    if (string.IsNullOrEmpty(Suffix))
                        return SelectedText.Trim();
                    else
                        return string.Format("{0} {1}", SelectedText.Trim(), Suffix);//only for code and error window, not xaml or references

                }
            }
        }
        public Context CreateContext(IProjectInfo prInf)
        {
            Context ctx = new Context() { Suffix = null, ProjectInfo = prInf,/*SP = this,*/ };
            return ctx;

        }
        protected virtual WindowPopupEnum DefaultSearchLocations
        {
            get
            {
                return Utils.AllPopUpWnds;
            }
        }
        public WindowPopupEnum SearchLocations
        {
            get
            {
                WindowPopupEnum loc = DefaultSearchLocations;
                RegistryKey reg = Registry.CurrentUser.OpenSubKey(string.Format("{0}\\{1}", Common.Utils.AppHive, Metadata.ProviderName), false);
                if (reg != null)
                {
                    object obj = reg.GetValue("SearchLocations", loc, RegistryValueOptions.None);
                    loc = (WindowPopupEnum)System.Convert.ToUInt32(obj);
                    loc &= Metadata.SupportedWnds;
                    reg.Close();
                }
                return loc;
            }
            set
            {
                RegistryKey reg = Registry.CurrentUser.CreateSubKey(string.Format("{0}\\{1}", Common.Utils.AppHive, Metadata.ProviderName), RegistryKeyPermissionCheck.Default);
                if (reg != null)
                {
                    reg.SetValue("SearchLocations", (uint)(value & Metadata.SupportedWnds), RegistryValueKind.DWord);
                    reg.Close();
                }

            }
        }

        public ISearchProviderMetaData Metadata { get; protected set; }

        public string GetNavigationUrl(Context context)
        {//add more from Context
            return Metadata.URL + Uri.EscapeUriString(context.SearchPhrase).Replace("#", "%23").Replace("/", "%2F").Replace("+", "%2B"); ;
        }
        internal SearchProvider()
        {
            if (this.GetType() != typeof(SearchProvider))
            {

                string type = this.GetType().Name;
                //convention class name = metadata SearchProviderName
                Metadata = MEFController.Instance.GetProviderSearchMetadata(type);
            }

        }
    }

    [ExportSearchProvider(ProviderName = "Google", Description = "Google search provider", URL = "http://www.google.com/search?q=",
SupportedWnds = Utils.AllPopUpWnds)]
    public sealed class Google : SearchProvider
    {
        protected override WindowPopupEnum DefaultSearchLocations
        {
            get
            {
                return WindowPopupEnum.CodeWindow | WindowPopupEnum.ErrorList | WindowPopupEnum.HTML | WindowPopupEnum.XAMLEditor;
            }
        }
        private Google()
        {
            // Metadata = MEFController.Instance.GetProviderSearchMetadata("Google");
        }
    }
    [ExportSearchProvider(ProviderName = "MSDN", Description = "MSDN search provider", URL = "http://social.msdn.microsoft.com/search/en-US?query=",
    SupportedWnds = Utils.AllPopUpWnds)]
    public sealed class MSDN : SearchProvider
    {
        protected override WindowPopupEnum DefaultSearchLocations
        {
            get
            {
                return WindowPopupEnum.CodeWindow | WindowPopupEnum.ErrorList | WindowPopupEnum.ReferenceItem;
            }
        }
        private MSDN()
        {
            // Metadata = MEFController.Instance.GetProviderSearchMetadata("MSDN");
        }
    }
    [ExportSearchProvider(ProviderName = "CodeProject", Description = "Code Project search provider", URL = "http://www.codeproject.com/search.aspx?q=",
    SupportedWnds = Utils.AllPopUpWnds)]
    public sealed class CodeProject : SearchProvider
    {
        protected override WindowPopupEnum DefaultSearchLocations
        {
            get
            {
                return WindowPopupEnum.CodeWindow;
            }
        }
        private CodeProject()
        {
            // Metadata = MEFController.Instance.GetProviderSearchMetadata("CodeProject");
        }
    }
    [ExportSearchProvider(ProviderName = "StackOverflow", Description = "Stack Overflow search provider", URL = "http://stackoverflow.com/search?q=",
    SupportedWnds = Utils.AllPopUpWnds)]
    public sealed class StackOverflow : SearchProvider
    {
        protected override WindowPopupEnum DefaultSearchLocations
        {
            get
            {
                return WindowPopupEnum.CodeWindow | WindowPopupEnum.ErrorList | WindowPopupEnum.HTML | WindowPopupEnum.XAMLEditor;
            }
        }
        private StackOverflow()
        {
            //  Metadata = MEFController.Instance.GetProviderSearchMetadata("StackOverflow");
        }
    }
    [ExportSearchProvider(ProviderName = "Yahoo", Description = "Yahoo search provider", URL = "http://search.yahoo.com/bin/search?p=",
    SupportedWnds = Utils.AllPopUpWnds)]
    public sealed class Yahoo : SearchProvider
    {
        protected override WindowPopupEnum DefaultSearchLocations
        {
            get
            {
                return WindowPopupEnum.CodeWindow;
            }
        }
        private Yahoo()
        {
            //  Metadata = MEFController.Instance.GetProviderSearchMetadata("Yahoo");
        }
    }
    [ExportSearchProvider(ProviderName = "Bing", Description = "Bing search provider", URL = "http://www.bing.com/search?q=",
    SupportedWnds = Utils.AllPopUpWnds)]
    public sealed class Bing : SearchProvider
    {
        protected override WindowPopupEnum DefaultSearchLocations
        {
            get
            {
                return WindowPopupEnum.CodeWindow | WindowPopupEnum.ErrorList | WindowPopupEnum.HTML | WindowPopupEnum.XAMLEditor | WindowPopupEnum.ReferenceItem;
            }
        }
        private Bing()
        {
            //  Metadata = MEFController.Instance.GetProviderSearchMetadata("Bing");
        }
    }
    [ExportSearchProvider(ProviderName = "Ask", Description = "Ask search provider", URL = "http://www.ask.com/web?q=",
    SupportedWnds = Utils.AllPopUpWnds)]
    public sealed class Ask : SearchProvider
    {
        protected override WindowPopupEnum DefaultSearchLocations
        {
            get
            {
                return WindowPopupEnum.CodeWindow;
            }
        }
        private Ask()
        {
            //  Metadata = MEFController.Instance.GetProviderSearchMetadata("Ask");
        }
    }


}
